package com.wnxy.sddfp.system.service.impl;

import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.wnxy.sddfp.common.exception.Assert;
import com.wnxy.sddfp.common.model.dto.bank.CardBindDto;
import com.wnxy.sddfp.common.model.dto.bank.SignatureDto;
import com.wnxy.sddfp.common.model.dto.user.LoginDto;
import com.wnxy.sddfp.common.model.vo.user.LoginVo;
import com.wnxy.sddfp.common.result.enums.impl.BusinessCode;
import com.wnxy.sddfp.common.utils.JwtTemplate;
import com.wnxy.sddfp.common.utils.TokenUtils;
import com.wnxy.sddfp.system.entity.User;
import com.wnxy.sddfp.system.entity.UserDetail;
import com.wnxy.sddfp.system.mapper.UserMapper;
import com.wnxy.sddfp.system.service.IUserDetailService;
import com.wnxy.sddfp.system.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wnxy.sddfp.common.model.dto.user.UserRegisterDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author yellow docker
 * @since 2025-05-06
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Autowired
    private IUserService userService;
    @Autowired
    private IUserDetailService userDetailService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private JwtTemplate jwtTemplate;
    @Autowired
    private IUserDetailService userDetailServiceImpl;
    @Override
    public void register(UserRegisterDto userRegistDto) {
       //1.判断这个手机号是否已注册
        User user=userService.getOne(Wrappers.lambdaQuery(User.class).eq(User::getPhone,userRegistDto.getPhone()));
        Assert.error(Objects.nonNull(user), BusinessCode.USER_EXISTED);
        registerUser(userRegistDto);
    }

    private void registerUser(UserRegisterDto userRegistDto) {
                User user1 = new User();
        user1.setUserName(userRegistDto.getUserName());
        user1.setPhone(userRegistDto.getPhone());
        //密码加密
//        String hashpw = BCrypt.hashpw(userRegistDto.getPwd());
//        BCrypt.checkpw(userRegistDto.getPwd(), hashpw);
        user1.setPwd(userRegistDto.getPwd());
        user1.setUserType("1");
        save(user1);


        //3、添加userDetail对象
        UserDetail userDetail = new UserDetail();
        userDetail.setId(user1.getId());
        userDetail.setUserName(userRegistDto.getUserName());
        userDetail.setPhone(userRegistDto.getPhone());
        userDetail.setBorrowMoney(new BigDecimal("0"));
        //用户码 随机数   UUID.randomUUID().toString().substring(0,12) 截取 12 位
        userDetail.setUserCode("UC_" + UUID.randomUUID().toString().substring(0,12));
        //是否绑卡 默认未绑卡 false
        userDetail.setCardBindStatus(false);

        userDetailService.save(userDetail);

    }

    @Override
    public LoginVo login(LoginDto loginDto) {
        return loginDto.getIsPhoneLogin()  ? loginByPhone(loginDto) : loginByUserName(loginDto);
    }

    /**
     * 用户名密码登录
     * @param loginDto
     * @return
     */
    private LoginVo loginByUserName(LoginDto loginDto) {
        //1、通过用户名查询用户
        User user = userService.getOne(new QueryWrapper<User>().eq("user_name", loginDto.getLoginName()));
        Assert.error(Objects.isNull(user), BusinessCode.USER_NOT_EXIST);
        //2.判断密码是否正确
        Assert.error(!user.getPwd().equals(loginDto.getLoginSecret()),  BusinessCode.USER_LOGIN_ERROR);
        //3.返回loginVo

        return createLoginVo(user);
    }

    private LoginVo createLoginVo(User user) {
        Map<String,Object>playload=new HashMap<>();
        playload.put("userId",user.getId());
        //创建token
        String token = jwtTemplate.createToken(playload);
        LoginVo loginVo = LoginVo.builder()
                .id(user.getId())
                .userName(user.getUserName())
                .phone(user.getPhone())
                .token(token)//返回token
                .build();
        String tokenKey="user:token:"+user.getId();
        //将token存储到redis中
        stringRedisTemplate.opsForValue().set(tokenKey,token, Duration.ofMinutes(30));

        return loginVo;
    }

    /**
     * 手机验证码登录
     * @param loginDto
     * @return
     */
    private LoginVo loginByPhone(LoginDto loginDto) {
        //1.登录校验验证码
        String codeKey="user:"+loginDto.getLoginName()+":"+loginDto.getLoginSecret();
        //加入redis缓存
        String code =stringRedisTemplate.opsForValue().get(codeKey);
        //验证码过期
        Assert.error(Objects.isNull(code), BusinessCode.USER_TIMEOUT_CODE_EXPIRED);
        //验证码错误
        Assert.error(!code.equals(loginDto.getLoginSecret()),BusinessCode.USER_VERIFY_CODE_ERROR);
        //判断用户是否存在，存在则直接登录，不存在则注册
        User user = userService.getOne(new QueryWrapper<User>().eq("phone", loginDto.getLoginName()));
        //如果用户不存在，则注册
        if(Objects.isNull(user)){
          //注册
            UserRegisterDto userRegisterDto = new UserRegisterDto();
            userRegisterDto.setUserName("user_:"+UUID.randomUUID().toString().substring(0,5));
            userRegisterDto.setPhone(loginDto.getLoginName());
            userRegisterDto.setPwd("123456");
            registerUser(userRegisterDto);

            //返回一个User刚刚注册的前端登录信息
          user=userService.getOne(new QueryWrapper<User>().eq("phone", loginDto.getLoginName()));
          //返回登录信息
          return createLoginVo(user);
        }
        LoginVo loginVo = createLoginVo(user);

        return loginVo;
    }

    /**
     * 绑卡的业务实现
     *
     *       用户绑卡：
     *       1、从token中获取userId
     *       2、校验：根据用户id查询u_user_detail用户表，根据CARD_BIND_STATUS字段判断是否已经绑卡
     *       3、如果未绑卡，保存保卡信息到u_user_card表
     *       4、更新用户表：把请求参数中的用户真实姓名、身份证号码更新到u_user表中
     *       5、生成请求流水号，用来访问托管代理，并更新u_user_detail表中流水号字段REQ_CODE
     *       6、远程访问托管代理服务（暂不实现）
     *
     *
     *
     */
    @Override
    public SignatureDto addBankAccount(CardBindDto cardBindDto) {
        //1、从token中获取userId
        String userId = TokenUtils.getTokenUserId("userId");

        return null;
    }
}

